home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
prog
/
asm_n_z.arj
/
SCRNFLIP.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-03-01
|
13KB
|
372 lines
; This program is described in BYTE, November 1983, Pages 99 - 116.
; Article is entitled "ENHANCING SCREEN DISPLAYS FOR THE IBM PC",
; author is Tim Field.
; Define interrupt vectors for both keyboard interrupt 16H and screen
; interrupt 10H. Both are in segment 0:
KEYVECT SEGMENT AT 0 ;Define KEYBOARD int. vector
ORG 16H*4
KEYINT LABEL DWORD
KEYVECT ENDS
SCRVECT SEGMENT AT 0 ;Define SCREEN int. vector
ORG 10H*4
SCRINT LABEL DWORD
SCRVECT ENDS
; Define constants:
BW_VAL EQU 07H ;Standard B&W attribute
EQUIP_FLAG EQU 410H ;RAM address of equipment stat
CHK_MODE EQU 15 ;INT fn: Check screen mode
MONO_MODE EQU 7 ;Mode 7 = monochrome monitor
COLOR_ADPT EQU 3 ;Modes 0-3: non-graphics color
; Start code area:
CODE SEGMENT PARA ;Start code at offset 100H
ASSUME CS:CODE ;from starting segment; leaves
ORG 100H ;room for PSP
KEY PROC FAR
; Initialization code - used only once during startup:
START:
JMP INIT_CODE ;Call initialization routine
; Define storage areas and data structures:
; Define keystroke scan codes for the five SCREEN functions:
FORE_INC DW 5E00H ;Foreground increment
BACK_INC DW 6000H ;Background increment
C80_40 DW 6200H ;80x25 to 40x25 flip-flop key
COL_MON DW 6400H ;COLOR/MONO flip-flop key
REPAINT DW 6600H ;Repaint scrn using curr. mode
CUR_MODE DW COL80_AREA ;Initialize starting mode
MONO_SET DW MONO_AREA ;Pointer to monochrome area
COLOR_SET DW COL80_AREA ;Pointer to active color area
SCRN_ATTR DB 70H ;Current screen attribute
SCRN_MODE DB 255 ;Save current screen mode
; Define structure used to contain information about 40 and 80 column color
; modes as well as monochrome mode:
S STRUC
CORNER DW 0 ;Defines COL/ROW count of
;characters for the monitor
BF DW 0 ;Colors of FORE and BACK
EQUIP DW 0 ;Equipment setting
MODE DW 0 ;AX value for setting the mode
S ENDS ;of the monitor
; Now set up three screen structures with default condition:
COL80_AREA S <5019H,0107H,20H,3> ;80x25 white FORE, blue BACK
COL40_AREA S <2819H,0107H,10H,1> ;40x25 brown FORE, black BACK
MONO_AREA S <5019H,0007H,30H,7> ;Monochrome, reverse video
KEY_CALL: DB 0EAH ;Far JMP address to KEYBOARD
DD 0 ;interrupt. See article
; Procedure KEY_RTNE intercepts keyboard interrupt and determines if the
; keystroke is one of the five SCREEN ones:
KEY_RTNE:
STI ;Turn on interrupts
CMP AH,0
JNE KEY_CALL
PUSH DS ;Save registers
PUSH BX
PUSH CX
PUSH DX
PUSH ES
PUSH DI
PUSH CS ;Point DS to CS segment by
POP DS ;PUSH / POP operation
ASSUME DS:CODE
INT_LOOP: ;IBM keyboard procedure
PUSHF ;expects an interrupt call
MOV BX,OFFSET KEY_CALL+1 ;Address to ROM keyboard code
CALL DWORD PTR [BX] ;Call keyboard routine
MOV BX,CUR_MODE ;Get current mode address
CMP AX,COL_MON ;See if COLOR/MON flip flop
JNE TEST_FORE ;key. Exit if not. Otherwise:
CMP BX,MONO_SET ;Flip flop screen mode
JE SET_COLOR ;If monochrome, swap to color
CMP MONO_SET,0 ;See if monochrome installed
JE NEXT_KEY ;Ignore command if not
MOV BX,MONO_SET ;Otherwise set up monochrome
JMP SHORT DO_CHG
SET_COLOR:
CMP COLOR_SET,0 ;See if COLOR monitor enabled
JE NEXT_KEY ;Skip if not
MOV BX,COLOR_SET ;Set up for color
DO_CHG:
CALL SCREEN_CHG ;Implement screen change
NEXT_KEY:
MOV AH,0 ;Set up to fetch keystroke
JMP INT_LOOP ;Fetch next key input
TEST_FORE:
PUSH AX ;Save registers
PUSH BX ;See if in GRAPHICS mode
MOV AH,CHK_MODE
INT 10H
POP BX ;Restore BX register
CMP AL,COLOR_ADPT ;If between 0-3, not graphics
JLE NOT_GRAPH
CMP AL,MONO_MODE ;Monochrome mode
JGE NOT_GRAPH
POP AX ;Restore stack
JMP DONE ;If color-graphics mode, do
NOT_GRAPH: ;not change modes
POP AX ;Restore AX
CMP AX,FORE_INC ;Increment FOREGROUND color?
JNE TEST_BACK ;Skip if not
CMP BX,COLOR_SET ;See if currently using color
JNE BW_FLOP ;If not, go deal with B&W
MOV AX,[BX].BF ;Gets BACK in AL, FORE in AH
EQ_FORE:
INC AL ;Increment FOREGROUND color
AND AL,7 ;Keep it within bounds
CMP AL,AH ;See if same as BACKGROUND
JE EQ_FORE ;Increment again if yes
MOV [BX].BF,AX ;Save back to structure
JMP DO_CHG ;Redraw the screen
TEST_BACK:
CMP AX,BACK_INC ;Increment BACKGROUND color?
JNE TEST_REPAINT ;Skip if not
CMP BX,COLOR_SET ;See if currently using color
JNE BW_FLOP ;If not, go deal with B&W
MOV AX,[BX].BF ;Gets BACK in AL, FORE in AH
EQ_BACK:
INC AH ;Increment BACKGROUND color
AND AH,7 ;Keep it within bounds
CMP AH,AL ;See if same as FOREGROUND
JE EQ_BACK ;Increment again if yes
MOV [BX].BF,AX ;Save back to structure
JMP DO_CHG ;Redraw the screen
BW_FLOP: ;Flip flop B&W monitor
MOV AX,[BX].BF ;BACK in AH, FORE in Al
XCHG AH,AL ;Swap FOREGROUND, BACKGROUND
MOV [BX].BF,AX ;Save back to structure
JMP DO_CHG ;Redraw the screen
TEST_REPAINT:
CMP AX,REPAINT ;Repaint the screen?
JE DO_CHG ;If yes, then repaint screen
TEST_80_40:
CMP AX,C80_40 ;80-40 flip flop key?
JNE DONE ;Exit if not
CMP BX,OFFSET COL40_AREA ;Is curr. pointer area 40x25?
JNE TST80 ;Skip if not
MOV BX,OFFSET COL80_AREA ;Otherwise, flip to 80x25
JMP SHORT SAVE_COL ;Save to COLOR_SET
TST80:
CMP BX,OFFSET COL80_AREA ;Is current 80x25 color?
JNE NEXT_KEY ;Ignore key if not
MOV BX,OFFSET COL40_AREA
SAVE_COL:
MOV COLOR_SET,BX ;Save to COLOR_SET
JMP SET_COLOR ;Implement
DONE:
POP DI ;Restore registers
POP ES
POP DX
POP CX
POP BX
POP DS
IRET ;Return from interrupt
KEY ENDP ;End of main routine
; This routine changes current monitor screen mode. On input, BX points to
; the current monitor structure:
SCREEN_CHG PROC NEAR
MOV AX,0 ;Get segment address for RAM
MOV ES,AX ;EQUIP_FLAG
MOV AX,ES:EQUIP_FLAG ;Get set of EQUIP flags
AND AL,0CFH ;Scrap current monitor flag
OR AX,[BX].EQUIP ;Set up new monitor flag
MOV ES:EQUIP_FLAG,AX ;Save back in RAM
MOV CUR_MODE,BX ;Indicate new mode
; Now set up attribute for FOREGROUND and BACKGROUND:
MOV DX,[BX].BF ;Get both FORE and BACK in DX
MOV CL,4 ;Shift count
SHL DH,CL ;Shift BACK into upper nibble
OR DH,DL ;Move FORE into lower nibble
MOV SCRN_ATTR,DH ;Save results
; See if we need to reset monitor (switching to new monitor?):
MOV AX,[BX].MODE ;Get screen mode
CMP AL,SCRN_MODE ;Compare with current mode
JE SET_ATTR ;Skip if the same
MOV SCRN_MODE,AL ;Otherwise, save current mode
INT 10H ;And reset to new monitor
SET_ATTR:
CALL CH_ATTR ;Change attributes of current
RET ;screen
SCREEN_CHG ENDP
; This routine repaints the active screen so that every character on the
; current screen is displayed with the new attributes. On input, BX points
; to the current monitor structure:
CH_ATTR PROC NEAR
; See if we need to redraw border for color mode
CMP BX,OFFSET MONO_SET ;In color?
JE NO_BORDER ;Skip border code if not
PUSH AX ;Save registers
PUSH BX
MOV BX,[BX].BF ;Get BACKGROUND color in BL
MOV BL,BH
MOV BH,0 ;Select border coloring
MOV AH,11 ;Fn. call: set color palette
INT 10H ;Execute VIDEO I/O interrupt
POP BX ;Restore registers
POP AX
NO_BORDER:
MOV AX,[BX].CORNER ;Get COL and ROW for current
MOV CORNR,AX ;Save in temporary data area
MOV AH,CHK_MODE ;Get page number
INT 10H
; BX contains the active page:
MOV AH,3 ;Get current cursor position
INT 10H
PUSH DX ;Save position on stack
XOR DX,DX ;Zero-out DX
MOV CX,1 ;Set up counter
MOV BL,SCRN_ATTR ;Get current attribute
REP_ATTR:
MOV AH,2 ;Set cursor position
INT 10H
MOV AH,8 ;Read next character
INT 10H
; AH contains the current character attribute:
AND AH,88H ;Get intensity bit
AND BL,77H ;Ensure attr. intensity is off
OR BL,AH ;Create current attribute
MOV AH,9 ;Display char. with new attr.
INT 10H
INC DL
CMP DL,TCOL ;Are we done with this column?
JLE REP_ATTR ;If so, jump
XOR DL,DL ;Otherwise, zero-out DL
INC DH ;Move to next row
CMP DH,TROW ;Are we done with this screen?
JLE REP_ATTR ;Loop until done
POP DX ;Restore orig. cursor position
MOV AH,2
INT 10H
RET
CORNR LABEL WORD
TROW DB 0 ;Temp. store for ROW
TCOL DB 0 ;Temp. store for COL
CH_ATTR ENDP
; This routine replaces the SCREEN interrupt so that it can intercept B&W
; character writes and change the display attributes:
SCR_RTNE PROC NEAR
STI
PUSH DS ;Save DS
PUSH CS ;Point DS to CS segment by
POP DS ;PUSH / POP operation
ASSUME DS:CODE
CMP AH,6 ;Spot SCROLLUP and SCROLLDOWN
JL NORMAL_SCR ;calls
CMP AH,7
JG NOT_SCROLL
SCROLL:
CALL GET_CH ;Update attribute for scroll
JMP NORMAL_SCR ;Now execute scroll
NOT_SCROLL:
CMP AH,9 ;Check for "WRITE ATTR / CHAR"
JNE NORMAL_SCR ;command. Send out any other
XCHG BH,BL ;commands as normal. Get attr.
CALL GET_CH ;in BL and update attribute
XCHG BH,BL ;Move attribute back to BH for
NORMAL_SCR: ;command
POP DS ;Restore DS segment register
JMP_SCR: DB 0EAH ;See article
DD 0
SCR_RTNE ENDP
; This routine replaces the B&W character with the current replacement
; attributes and allows for the INTENSITY bit setting. On input, BH
; contains the attribute to be modified:
GET_CH PROC NEAR
MOV SAVECH,BH ;Save character
AND BH,77H ;Remove intensity / blink bits
CMP BH,BW_VAL ;See if cur. defined B&W value
MOV BH,SAVECH ;Otherwise, modify to current
JNE OUT ;attribute. Exit if not
AND BH,88H ;Get rid of B&W part
OR BH,SCRN_ATTR ;Move in current attr. part
OUT:
RET ;Done
SAVECH DB 0 ;Temporary character store
GET_CH ENDP
; All code after this label is freed to DOS use after this program has been
; initialized:
LASTONE:
; This routine loads and initializes the SCREEN program. It sets up DOS to
; keep all code before the label LASTONE safe from overlay during normal
; system operation:
INIT_CODE PROC NEAR
; Initialize KEYBOARD intercept code:
MOV AX,KEYVECT ;Point ES to interrupt vectors
MOV ES,AX ;(segment at 0H)
ASSUME ES:KEYVECT
MOV AX,ES:KEYINT ;Get address of interrupt
MOV BX,OFFSET KEY_CALL+1 ;vector and save both the
MOV [BX],AX ;segment and offset values of
MOV AX,ES:KEYINT[2] ;this routine in our data area
MOV [BX+2],AX ;Now, replace the original
MOV ES:KEYINT,OFFSET KEY_RTNE ;interrupt vector with the
MOV AX,CS ;address of our own routine
MOV ES:KEYINT[2],AX
; Initialize SCREEN intercept code:
MOV AX,SCRVECT ;Point ES to interrupt vectors
MOV ES,AX ;(segment at 0H)
ASSUME ES:SCRVECT
MOV AX,ES:SCRINT ;Get address of interrupt
MOV BX,OFFSET JMP_SCR+1 ;vector and save both the
MOV [BX],AX ;segment and offset values of
MOV AX,ES:SCRINT[2] ;this routine in our data area
MOV [BX+2],AX ;Now, replace the original
MOV ES:SCRINT,OFFSET SCR_RTNE ;interrupt vector with the
MOV AX,CS ;address of our own routine
MOV ES:SCRINT[2],AX
; Initialize screen:
MOV BX,CUR_MODE ;Set up initial screen mode
CALL SCREEN_CHG ;Initialize screen mode
; Now, terminate and stay resident:
MOV DX,OFFSET LASTONE ;Save all code up to LASTONE
INT 27H ;Terminate and stay resident
INIT_CODE ENDP
CODE ENDS
END START